package ui.controls.tree.news
{
	public class Node
	{
		protected var nodeInfoCache:NodeInfoCache;
		
		protected var parentNode:Node;
		
		private var childList:Array;
		
		private var expanded:Boolean;
		
		private var _data:*;
		
		private var _level:int;
		
		public function Node(data:* , _nodeInfoCache:NodeInfoCache):void
		{
			_data = data;
			if(_nodeInfoCache == null)
				_nodeInfoCache = new NodeInfoCache();
			nodeInfoCache = _nodeInfoCache;
		}
		
		public function getAllNodeCount():int
		{
			return nodeInfoCache.getNodeCount();
		}
		
		public function getAllVisibleNodeCount():int
		{
			return nodeInfoCache.getVisibleNodeCount();
		}
		
		public function getParent():Node
		{
			return parentNode;
		}
		
		public function getPath():Array
		{
			var arr:Array = [];
			var node:Node = this;
			while(node.getParent())
			{
				arr.splice(0,0,node.data);
				node = node.getParent();
			}
			return arr;
		}
		
		public function get data():*
		{
			return _data;
		}
		
		public function get childCount():int
		{
			if(childList == null)
				return 0;
			return childList.length;
		}
		
		public function createChild(value:*,level:int):Node
		{
			if(childList == null)
				childList = [];
			var node:Node = new Node(value , nodeInfoCache); 
			node.parentNode = this;
			node._level = level;
			childList.push(node);
			nodeInfoCache.addNode(node);
			return node;
		}
		
		public function getChild(value:*):Node
		{
			if(childList == null)
				return null;
			var node:Node = null;
			for(var i:int=0;i<childList.length;i++)
			{
				node = childList[i];
				if(node.data == value)
				{
					return node;
				}
			}
			return null;
		}
		
		public function getChildAt(value:int):Node
		{
			if(childList == null)
				return null;
			return childList[value];
		}
		
		public function getChildIndex(value:Node):int
		{
			if(childList == null)
				return -1;
			return childList.indexOf(value);
		}
		
		public function deleteChild(value:*):Node
		{
			if(childList == null)
				return null;
			var node:Node = null;
			for(var i:int=0;i<childList.length;i++)
			{
				node = childList[i];
				if(node.data == value)
				{
					childList.splice(i , 1)[0];
					nodeInfoCache.removeNode(node);
					return node;
				}
			}
			return null;
		}
		
		public function set expand(value:Boolean):void
		{
			if(childList == null)
				return;
			if(expanded != value)
			{
				expanded = value;
				if(expanded)
					nodeInfoCache.expandCalculate(this);
				else
					nodeInfoCache.foldCalculate(this);
			}
		}
		
		public function get expand():Boolean
		{
			return expanded;
		}
		
		public function get level():int
		{
			return _level;
		}
		
	}
}

import flash.utils.Dictionary;
import ui.controls.tree.news.Node;


class NodeInfoCache
{
	private var visibleNodeCache:Dictionary;
	
	private var nodeCount:int = 0;
	
	private var visibleCount:int = 0;
	
	public function NodeInfoCache()
	{
		visibleNodeCache = new Dictionary();
	}
	
	public function addNode(value:Node):void
	{
		if(visibleNodeCache[value.getParent()])
		{
			visibleNodeCache[value] = true;
			visibleCount += 1;
		}
		nodeCount += 1;
	}
	
	public function removeNode(value:Node):void
	{
		var childCount:int = value.childCount;
		nodeCount -= childCount + 1;
		if(visibleNodeCache[value])
		{
			delete visibleNodeCache[value];
			visibleCount -= 1;
		}
		
		var node:Node;
		for(var i:int=0;i<childCount;i++)
		{
			node = value.getChildAt(i);
			removeNode(node);
		}
	}
	
	public function expandCalculate(value:Node):void
	{
		var childCount:int = value.childCount;
		visibleCount += childCount;
		
		var node:Node;
		for(var i:int=0;i<childCount;i++)
		{
			node = value.getChildAt(i);
			visibleNodeCache[node] = true;
			if(node.expand)
				expandCalculate(node);
		}
	}
	
	public function foldCalculate(value:Node):void
	{
		var childCount:int = value.childCount;
		visibleCount -= childCount;
		var node:Node;
		for(var i:int=0;i<childCount;i++)
		{
			node = value.getChildAt(i);
			
			if(visibleNodeCache[node])
			{
				delete visibleNodeCache[node];
			}
			
			if(node.expand)
				foldCalculate(node);
		}
	}
	
	public function getNodeCount():int
	{
		return nodeCount;
	}
	
	public function getVisibleNodeCount():int
	{
		return visibleCount;
	}
	
}